﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO; // 用于文件读取
using System.Text; // 用于 StringBuilder

// --- 使用别名解决命名空间冲突 ---
using WinForms = System.Windows.Forms;
using Drawing = System.Drawing;

// Revit API 命名空间
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical; // Space 类在这里
using Autodesk.Revit.DB.Analysis;   // HVACLoadSpaceType 类在这里
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.Attributes;

namespace RevitApiExample // <--- 确保这是你项目的正确命名空间
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class SPTestImportSpaceTypesCommand : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Document doc = uidoc.Document;

            // --- 1. 选择 CSV 文件 ---
            string csvFilePath = string.Empty;
            using (WinForms.OpenFileDialog openFileDialog = new WinForms.OpenFileDialog())
            {
                openFileDialog.Filter = "CSV 文件 (*.csv)|*.csv|所有文件 (*.*)|*.*";
                openFileDialog.Title = "选择包含空间类型定义的 CSV 文件";
                // 使用别名访问 DialogResult
                if (openFileDialog.ShowDialog() == WinForms.DialogResult.OK)
                {
                    csvFilePath = openFileDialog.FileName;
                }
                else
                {
                    return Result.Cancelled; // 用户取消选择
                }
            }

            // --- 2. 读取和解析 CSV 数据 ---
            List<SpaceTypeData> typesToImport = new List<SpaceTypeData>();
            string[] lines;
            try
            {
                // 尝试使用 UTF-8 读取，如果失败，再尝试默认编码，增加兼容性
                try
                {
                    lines = File.ReadAllLines(csvFilePath, Encoding.UTF8);
                }
                catch
                {
                    lines = File.ReadAllLines(csvFilePath, Encoding.Default);
                }
            }
            catch (Exception ex)
            {
                message = $"读取文件失败: {ex.Message}";
                return Result.Failed;
            }

            if (lines.Length < 2)
            {
                message = "CSV 文件为空或只有表头。";
                return Result.Failed;
            }

            string headerLine = lines[0];
            // 简单的逗号分割，对于复杂CSV可能不够健壮
            string[] headers = headerLine.Split(',');

            // 获取表头索引，忽略大小写并去除空格
            Dictionary<string, int> headerIndexMap = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
            for (int i = 0; i < headers.Length; i++)
            {
                string header = headers[i].Trim();
                if (!string.IsNullOrEmpty(header) && !headerIndexMap.ContainsKey(header))
                {
                    headerIndexMap.Add(header, i);
                }
            }

            // 验证必需的表头
            if (!headerIndexMap.ContainsKey("Name"))
            {
                message = "CSV 文件缺少必需的表头列: 'Name'。";
                return Result.Failed;
            }


            StringBuilder parseErrors = new StringBuilder();
            for (int i = 1; i < lines.Length; i++) // 从第二行开始是数据
            {
                string line = lines[i];
                if (string.IsNullOrWhiteSpace(line)) continue; // 跳过空行

                // 简单的逗号分割
                string[] values = line.Split(',');

                // 简单检查列数是否足够 Name 列存在
                if (values.Length <= headerIndexMap["Name"])
                {
                    parseErrors.AppendLine($"第 {i + 1} 行数据列数不足，已跳过。");
                    continue;
                }


                SpaceTypeData data = new SpaceTypeData();
                try
                {
                    data.Name = GetValue(values, headerIndexMap, "Name");
                    if (string.IsNullOrWhiteSpace(data.Name))
                    {
                        parseErrors.AppendLine($"第 {i + 1} 行缺少名称，已跳过。");
                        continue;
                    }

                    // 解析数据，如果列不存在或解析失败，对应属性将为 null 或默认值
                    data.IsPlenum = ParseBool(GetValue(values, headerIndexMap, "IsPlenum"), false);
                    data.AreaPerPerson_m2_person = ParseDouble(GetValue(values, headerIndexMap, "AreaPerPerson_m2_person"));
                    data.LightingLoadDensity_W_m2 = ParseDouble(GetValue(values, headerIndexMap, "LightingLoadDensity_W_m2"));
                    data.PowerLoadDensity_W_m2 = ParseDouble(GetValue(values, headerIndexMap, "PowerLoadDensity_W_m2"));
                    data.SensibleHeatGainPerPerson_W = ParseDouble(GetValue(values, headerIndexMap, "SensibleHeatGainPerPerson_W"));
                    data.LatentHeatGainPerPerson_W = ParseDouble(GetValue(values, headerIndexMap, "LatentHeatGainPerPerson_W"));
                    data.HeatingSetpoint_C = ParseDouble(GetValue(values, headerIndexMap, "HeatingSetpoint_C"));
                    data.CoolingSetpoint_C = ParseDouble(GetValue(values, headerIndexMap, "CoolingSetpoint_C"));

                    typesToImport.Add(data);
                }
                catch (Exception ex)
                {
                    parseErrors.AppendLine($"解析第 {i + 1} 行数据时出错 (名称: {GetValue(values, headerIndexMap, "Name", "未知")}): {ex.Message}");
                }
            }

            if (parseErrors.Length > 0)
            {
                // 使用 TaskDialog 显示解析警告
                TaskDialog parseWarnDialog = new TaskDialog("解析警告");
                parseWarnDialog.MainInstruction = "处理 CSV 文件时遇到一些问题";
                parseWarnDialog.MainContent = "将继续尝试导入有效数据。";
                parseWarnDialog.ExpandedContent = parseErrors.ToString();
                parseWarnDialog.CommonButtons = TaskDialogCommonButtons.Ok;
                parseWarnDialog.Show();
            }

            if (typesToImport.Count == 0)
            {
                message = "未能从 CSV 文件中解析出任何有效的空间类型数据。";
                // 使用 TaskDialog 显示错误
                TaskDialog.Show("导入失败", message);
                return Result.Failed;
            }

            // --- 3. 批量创建和设置 ---
            int createdCount = 0;
            int skippedCount = 0;
            int errorCount = 0;
            StringBuilder importLog = new StringBuilder();

            using (Transaction tx = new Transaction(doc, "批量导入空间类型"))
            {
                tx.Start();
                try
                {
                    foreach (var data in typesToImport)
                    {
                        // 检查名称是否唯一，忽略大小写比较可能更友好
                        bool isNameUnique = !new FilteredElementCollector(doc)
                                                .OfClass(typeof(HVACLoadSpaceType))
                                                .Cast<HVACLoadSpaceType>()
                                                .Any(st => st.Name.Equals(data.Name, StringComparison.OrdinalIgnoreCase));

                        // 或者使用 API 提供的方法 (如果确定它按预期工作)
                        // bool isNameUnique = HVACLoadSpaceType.IsNameUnique(doc, data.Name);


                        if (isNameUnique)
                        {
                            HVACLoadSpaceType newType = null;
                            try
                            {
                                // 创建新的空间类型
                                newType = HVACLoadSpaceType.Create(doc, data.Name);

                                // 设置属性 (注意单位转换!)

                                // IsPlenum 是只读的，不能直接设置
                                // 可以考虑通过名称判断，例如 "XXX - Plenum"，然后在需要时查找特定参数设置（如果存在）
                                // // newType.IsPlenum = data.IsPlenum; // CS0200: Property is read-only

                                // AreaPerPerson - API 需要内部单位 ft²/person
                                if (data.AreaPerPerson_m2_person.HasValue && data.AreaPerPerson_m2_person > 0) // 避免传入0或负值
                                {
                                    // 从 m²/person (CSV单位) 转换为 ft²/person (Revit内部单位)
                                    double areaPerPersonInternal = UnitUtils.ConvertToInternalUnits(
                                        data.AreaPerPerson_m2_person.Value,
                                        UnitTypeId.SquareMeters); // 使用面积单位类型
                                    newType.AreaPerPerson = areaPerPersonInternal;
                                }

                                // LightingLoadDensity - API 需要内部单位 W/ft²
                                if (data.LightingLoadDensity_W_m2.HasValue)
                                {
                                    double lightingDensityInternal = UnitUtils.ConvertToInternalUnits(
                                        data.LightingLoadDensity_W_m2.Value,
                                        UnitTypeId.WattsPerSquareMeter);
                                    newType.LightingLoadDensity = lightingDensityInternal;
                                }

                                // PowerLoadDensity - API 需要内部单位 W/ft²
                                if (data.PowerLoadDensity_W_m2.HasValue)
                                {
                                    double powerDensityInternal = UnitUtils.ConvertToInternalUnits(
                                        data.PowerLoadDensity_W_m2.Value,
                                        UnitTypeId.WattsPerSquareMeter);
                                    newType.PowerLoadDensity = powerDensityInternal;
                                }

                                // SensibleHeatGainPerPerson - API 需要内部单位 BTU/h
                                if (data.SensibleHeatGainPerPerson_W.HasValue)
                                {
                                    double sensibleGainInternal = UnitUtils.ConvertToInternalUnits(
                                        data.SensibleHeatGainPerPerson_W.Value,
                                        UnitTypeId.Watts);
                                    newType.SensibleHeatGainPerPerson = sensibleGainInternal;
                                }

                                // LatentHeatGainPerPerson - API 需要内部单位 BTU/h
                                if (data.LatentHeatGainPerPerson_W.HasValue)
                                {
                                    double latentGainInternal = UnitUtils.ConvertToInternalUnits(
                                        data.LatentHeatGainPerPerson_W.Value,
                                        UnitTypeId.Watts);
                                    newType.LatentHeatGainPerPerson = latentGainInternal;
                                }

                                // HeatingSetpoint - API 需要内部单位 K
                                if (data.HeatingSetpoint_C.HasValue)
                                {
                                    double heatingSetpointInternal = UnitUtils.ConvertToInternalUnits(
                                        data.HeatingSetpoint_C.Value,
                                        UnitTypeId.Celsius);
                                    newType.HeatingSetPoint = heatingSetpointInternal;
                                }

                                // CoolingSetpoint - API 需要内部单位 K
                                if (data.CoolingSetpoint_C.HasValue)
                                {
                                    double coolingSetpointInternal = UnitUtils.ConvertToInternalUnits(
                                        data.CoolingSetpoint_C.Value,
                                        UnitTypeId.Celsius);
                                    newType.CoolingSetPoint = coolingSetpointInternal;
                                }

                                createdCount++;
                                importLog.AppendLine($"成功: 创建并设置了 '{data.Name}'");
                            }
                            catch (Exception ex)
                            {
                                errorCount++;
                                importLog.AppendLine($"错误: 创建或设置属性时失败 '{data.Name}': {ex.Message}");
                                // 考虑是否需要删除部分成功的创建，但通常让用户手动清理更好
                            }
                        }
                        else
                        {
                            skippedCount++;
                            importLog.AppendLine($"跳过: 名称 '{data.Name}' 已存在");
                        }
                    } // end foreach

                    tx.Commit();
                }
                catch (Exception ex)
                {
                    // 事务中发生严重错误，回滚所有更改
                    tx.RollBack();
                    message = $"导入过程中发生严重错误，所有更改已回滚: {ex.Message}";
                    TaskDialog.Show("导入失败", message + "\n\n详细日志:\n" + importLog.ToString());
                    return Result.Failed;
                }
            } // end using Transaction

            // --- 4. 显示结果 ---
            string summary = $"导入完成。\n\n成功创建: {createdCount}\n跳过 (名称已存在): {skippedCount}\n失败: {errorCount}\n";
            TaskDialog mainDialog = new TaskDialog("导入结果");
            mainDialog.MainInstruction = summary;
            if (importLog.Length > 0) // 只在有日志时显示详细信息
            {
                mainDialog.MainContent = "详细导入日志:";
                mainDialog.ExpandedContent = importLog.ToString();
            }
            else
            {
                mainDialog.MainContent = "没有详细的导入日志。";
            }
            mainDialog.CommonButtons = TaskDialogCommonButtons.Ok;
            mainDialog.Show();

            return Result.Succeeded;
        } // end Execute

        // --- 辅助方法 ---

        /// <summary>
        /// 安全地从值数组中根据表头名称获取值
        /// </summary>
        private string GetValue(string[] values, Dictionary<string, int> headerIndexMap, string headerName, string defaultValue = "")
        {
            // 使用 Trim() 清除可能的空格
            if (headerIndexMap.TryGetValue(headerName.Trim(), out int index))
            {
                if (index < values.Length && !string.IsNullOrWhiteSpace(values[index]))
                {
                    // 再次 Trim() 清除值两端的空格
                    return values[index].Trim();
                }
            }
            return defaultValue;
        }

        /// <summary>
        /// 尝试将字符串解析为 double? (可空类型)
        /// </summary>
        private double? ParseDouble(string value)
        {
            if (double.TryParse(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double result))
            {
                return result;
            }
            return null; // 解析失败或值为空，返回 null
        }

        /// <summary>
        /// 尝试将字符串解析为 bool
        /// </summary>
        private bool ParseBool(string value, bool defaultValue)
        {
            if (string.IsNullOrWhiteSpace(value)) return defaultValue;
            value = value.Trim().ToLowerInvariant();
            if (value == "true" || value == "yes" || value == "1") return true;
            if (value == "false" || value == "no" || value == "0") return false;
            // 可以添加对中文或其他语言的支持，例如：
            // if (value == "是") return true;
            // if (value == "否") return false;
            return defaultValue; // 无法识别，返回默认值
        }
    } // end class ImportSpaceTypesCommand

    /// <summary>
    /// 用于临时存储从 CSV 读取的数据的辅助类
    /// 使用 可空类型 (nullable types, e.g., double?) 来表示 CSV 中可能缺失的值
    /// </summary>
    public class SpaceTypeData
    {
        public string Name { get; set; }
        public bool IsPlenum { get; set; } // 虽然不能直接设置，但可以读取用于其他逻辑
        public double? AreaPerPerson_m2_person { get; set; }
        public double? LightingLoadDensity_W_m2 { get; set; }
        public double? PowerLoadDensity_W_m2 { get; set; }
        public double? SensibleHeatGainPerPerson_W { get; set; }
        public double? LatentHeatGainPerPerson_W { get; set; }
        public double? HeatingSetpoint_C { get; set; }
        public double? CoolingSetpoint_C { get; set; }
        // 添加更多你需要的属性...
    }


    // --- CS0101 & CS0111 修正: ---
    // --- 确保 SpaceSelectionFilter 类只在一个地方定义! ---
    // --- 下面的代码块假设你在项目的其他地方定义了 SpaceSelectionFilter ---
    // --- 如果没有，请取消下面的注释块，并确保在其他文件中没有定义 ---
    /*
    public class SpaceSelectionFilter : ISelectionFilter
    {
         public bool AllowElement(Element elem)
        {
            // 只允许选择 Autodesk.Revit.DB.Mechanical.Space 类型的图元
            return elem is Space;
        }

        public bool AllowReference(Reference reference, XYZ position)
        {
            // 我们是按图元选择，不是按几何引用，所以返回 false
            return false;
        }
    }
    */

} // end namespace RevitApiExample